home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / GIFLIB12.ARJ / GIFCOMB.C < prev    next >
C/C++ Source or Header  |  1991-05-12  |  13KB  |  323 lines

  1. /*****************************************************************************
  2. *   "Gif-Lib" - Yet another gif library.                     *
  3. *                                         *
  4. * Written by:  Gershon Elber                Ver 0.1, Jul. 1989   *
  5. ******************************************************************************
  6. * Program to combine 2 GIF images into single one, using optional mask GIF   *
  7. * file. Result colormap will be the union of the two images colormaps.         *
  8. * Both images should have exactly the same size, although they may be mapped *
  9. * differently on screen. Only First GIF screen descriptor info. is used.     *
  10. * Options:                                     *
  11. * -q : quite printing mode.                             *
  12. * -m mask : optional boolean image, defines where second GIF should be used. *
  13. * -h : on line help.                                 *
  14. ******************************************************************************
  15. * History:                                     *
  16. * 12 Jul 89 - Version 1.0 by Gershon Elber.                     *
  17. *****************************************************************************/
  18.  
  19. #ifdef __MSDOS__
  20. #include <stdlib.h>
  21. #include <alloc.h>
  22. #endif /* _MSDOS__ */
  23.  
  24. #include <stdio.h>
  25. #include <ctype.h>
  26. #include <string.h>
  27. #include "gif_lib.h"
  28. #include "getarg.h"
  29.  
  30. #define PROGRAM_NAME    "GifComb"
  31.  
  32. #ifdef __MSDOS__
  33. extern unsigned int
  34.     _stklen = 16384;                 /* Increase default stack size. */
  35. #endif /* __MSDOS__ */
  36.  
  37. #ifdef SYSV
  38. static char *VersionStr =
  39.         "Gif library module,\t\tGershon Elber\n\
  40.     (C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
  41. static char
  42.     *CtrlStr = "GifComb q%- m%-MaskGIFFile!s h%- GifFile!*s";
  43. #else
  44. static char
  45.     *VersionStr =
  46.     PROGRAM_NAME
  47.     GIF_LIB_VERSION
  48.     "    Gershon Elber,    "
  49.     __DATE__ ",   " __TIME__ "\n"
  50.     "(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
  51. static char
  52.     *CtrlStr =
  53.     PROGRAM_NAME
  54.     " q%- m%-MaskGIFFile!s h%- GifFile!*s";
  55. #endif /* SYSV */
  56.  
  57. static int ReadUntilImage(GifFileType *GifFile);
  58. static int UnionColorMap(GifColorType *ColorIn1, int ColorIn1Size,
  59.              GifColorType *ColorIn2, int ColorIn2Size,
  60.              GifColorType **ColorUnionPtr, int *ColorUnionSize,
  61.              GifPixelType ColorTransIn2[]);
  62. static void QuitGifError(GifFileType *GifFileIn1, GifFileType *GifFileIn2,
  63.              GifFileType *GifMaskFile, GifFileType *GifFileOut);
  64.  
  65. /******************************************************************************
  66. * Interpret the command line and scan the given GIF file.              *
  67. ******************************************************************************/
  68. void main(int argc, char **argv)
  69. {
  70.     int    i, j, Error, NumFiles, Size, ColorUnionSize,
  71.     ColorIn1Size = 0, ColorIn2Size = 0,
  72.     MaskFlag = FALSE, HelpFlag = FALSE;
  73.     char **FileName = NULL, *MaskFileName;
  74.     GifPixelType ColorTransIn2[256];
  75.     GifRowType LineIn1 = NULL, LineIn2 = NULL, LineMask = NULL, LineOut = NULL;
  76.     GifColorType *ColorIn1 = NULL, *ColorIn2 = NULL, *ColorUnion;
  77.     GifFileType *GifFileIn1 = NULL, *GifFileIn2 = NULL, *GifMaskFile = NULL,
  78.     *GifFileOut = NULL;
  79.  
  80.     if ((Error = GAGetArgs(argc, argv, CtrlStr,
  81.         &GifQuitePrint, &MaskFlag, &MaskFileName,
  82.         &HelpFlag, &NumFiles, &FileName)) != FALSE ||
  83.         (NumFiles != 2 && !HelpFlag)) {
  84.     if (Error)
  85.         GAPrintErrMsg(Error);
  86.     else if (NumFiles != 2)
  87.         GIF_MESSAGE("Error in command line parsing - two GIF file please.");
  88.     GAPrintHowTo(CtrlStr);
  89.     exit(1);
  90.     }
  91.  
  92.     if (HelpFlag) {
  93.     fprintf(stderr, VersionStr);
  94.     GAPrintHowTo(CtrlStr);
  95.     exit(0);
  96.     }
  97.  
  98.     /* Open all input files (two GIF to combine, and optional mask): */
  99.     if ((GifFileIn1 = DGifOpenFileName(FileName[0])) == NULL ||
  100.     (GifFileIn2 = DGifOpenFileName(FileName[1])) == NULL ||
  101.     (MaskFlag && (GifMaskFile = DGifOpenFileName(MaskFileName)) == NULL))
  102.     QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut);
  103.  
  104.     if (ReadUntilImage(GifFileIn1) == GIF_ERROR ||
  105.     ReadUntilImage(GifFileIn2) == GIF_ERROR ||
  106.     (MaskFlag && ReadUntilImage(GifMaskFile) == GIF_ERROR))
  107.     QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut);
  108.  
  109.     if (GifFileIn1 -> IWidth != GifFileIn2 -> IWidth ||
  110.     GifFileIn2 -> IHeight != GifFileIn2 -> IHeight ||
  111.     (MaskFlag && (GifFileIn1 -> IWidth != GifMaskFile -> IWidth ||
  112.               GifFileIn1 -> IHeight != GifMaskFile -> IHeight)))
  113.     GIF_EXIT("Given GIF files have different image dimensions.");
  114.  
  115.     /* Open stdout for the output file: */
  116.     if ((GifFileOut = EGifOpenFileHandle(1)) == NULL)
  117.     QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut);
  118.  
  119.     Size = sizeof(GifPixelType) * GifFileIn1 -> IWidth;
  120.     if ((LineIn1 = (GifRowType) malloc(Size)) == NULL ||
  121.     (LineIn2 = (GifRowType) malloc(Size)) == NULL ||
  122.     (MaskFlag && (LineMask = (GifRowType) malloc(Size)) == NULL) ||
  123.     (LineOut = (GifRowType) malloc(Size)) == NULL)
  124.     GIF_EXIT("Failed to allocate memory required, aborted.");
  125.  
  126.     if (GifFileIn1 -> IColorMap) {
  127.     ColorIn1 = GifFileIn1 -> IColorMap;
  128.     ColorIn1Size = 1 << GifFileIn1 -> IBitsPerPixel;
  129.     }
  130.     else if (GifFileIn1 -> SColorMap) {
  131.     ColorIn1 = GifFileIn1 -> SColorMap;
  132.     ColorIn1Size = 1 << GifFileIn1 -> SBitsPerPixel;
  133.     }
  134.     else
  135.     GIF_EXIT("Neither Screen nor Image color map exists - GIF file 1.");
  136.  
  137.     if (GifFileIn2 -> IColorMap) {
  138.     ColorIn2 = GifFileIn2 -> IColorMap;
  139.     ColorIn2Size = 1 << GifFileIn2 -> IBitsPerPixel;
  140.     }
  141.     else if (GifFileIn2 -> SColorMap) {
  142.     ColorIn2 = GifFileIn2 -> SColorMap;
  143.     ColorIn2Size = 1 << GifFileIn2 -> SBitsPerPixel;
  144.     }
  145.     else
  146.     GIF_EXIT("Neither Screen nor Image color map exists - GIF file 2.");
  147.  
  148.     /* Create union of the two given color maps. ColorIn1 will be copied as  */
  149.     /* is while ColorIn2 will be mapped using ColorTransIn2 table.         */
  150.     /* ColorUnion is allocated by the procedure itself.                 */
  151.     if (UnionColorMap(ColorIn1, ColorIn1Size, ColorIn2, ColorIn2Size,
  152.         &ColorUnion, &ColorUnionSize, ColorTransIn2) == GIF_ERROR)
  153.     GIF_EXIT("Unioned color map is two big (>256 colors).");
  154.  
  155.     /* Dump out new image and screen descriptors: */
  156.     if (EGifPutScreenDesc(GifFileOut,
  157.     GifFileIn1 -> SWidth, GifFileIn1 -> SHeight,
  158.     ColorUnionSize, GifFileIn1 -> SBackGroundColor,
  159.     ColorUnionSize, ColorUnion) == GIF_ERROR)
  160.     QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut);
  161.     free((char *) ColorUnion);            /* We dont need this any more... */
  162.  
  163.     if (EGifPutImageDesc(GifFileOut,
  164.     GifFileIn1 -> ILeft, GifFileIn1 -> ITop,
  165.     GifFileIn1 -> IWidth, GifFileIn1 -> IHeight,
  166.     GifFileIn1 -> IInterlace, GifFileIn1 -> IBitsPerPixel, NULL) == GIF_ERROR)
  167.     QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut);
  168.  
  169.  
  170.     /* Time to do it: read 2 scan lines from 2 files (and optionally from    */
  171.     /* the mask file, merge them and them result out. Do it Height times:    */
  172.     GifQprintf("\n%s: Image 1 at (%d, %d) [%dx%d]:     ",
  173.     PROGRAM_NAME, GifFileOut -> ILeft, GifFileOut -> ITop,
  174.                 GifFileOut -> IWidth, GifFileOut -> IHeight);
  175.     for (i = 0; i < GifFileIn1 -> IHeight; i++) {
  176.     if (DGifGetLine(GifFileIn1, LineIn1, GifFileIn1 -> IWidth) == GIF_ERROR ||
  177.         DGifGetLine(GifFileIn2, LineIn2, GifFileIn2 -> IWidth) == GIF_ERROR ||
  178.         (MaskFlag &&
  179.          DGifGetLine(GifMaskFile, LineMask, GifMaskFile -> IWidth)
  180.                                 == GIF_ERROR))
  181.         QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut);
  182.     if (MaskFlag) {
  183.         /* Every time Mask has non background color, use LineIn1 pixel,  */
  184.         /* otherwise use LineIn2 pixel instead.                 */
  185.         for (j = 0; j < GifFileIn1 -> IWidth; j++) {
  186.         if (LineMask[j] != GifMaskFile -> SBackGroundColor)
  187.             LineOut[j] = LineIn1[j];
  188.         else
  189.             LineOut[j] = ColorTransIn2[LineIn2[j]];
  190.         }
  191.     }
  192.     else {
  193.         /* Every time Color of Image 1 is equal to background - take it  */
  194.         /* From Image 2 instead of the background.                 */
  195.         for (j = 0; j < GifFileIn1 -> IWidth; j++) {
  196.         if (LineIn1[j] != GifFileIn1 -> SBackGroundColor)
  197.             LineOut[j] = LineIn1[j];
  198.         else
  199.             LineOut[j] = ColorTransIn2[LineIn2[j]];
  200.         }
  201.     }
  202.     if (EGifPutLine(GifFileOut, LineOut, GifFileOut -> IWidth)
  203.                                 == GIF_ERROR)
  204.     QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut);
  205.     GifQprintf("\b\b\b\b%-4d", i);
  206.     }
  207.  
  208.     if (DGifCloseFile(GifFileIn1) == GIF_ERROR ||
  209.     DGifCloseFile(GifFileIn2) == GIF_ERROR ||
  210.     EGifCloseFile(GifFileOut) == GIF_ERROR ||
  211.     (MaskFlag && DGifCloseFile(GifMaskFile) == GIF_ERROR))
  212.     QuitGifError(GifFileIn1, GifFileIn2, GifMaskFile, GifFileOut);
  213. }
  214.  
  215. /******************************************************************************
  216. * Read until first image in GIF file is detected and read its descriptor.     *
  217. ******************************************************************************/
  218. static int ReadUntilImage(GifFileType *GifFile)
  219. {
  220.     int ExtCode;
  221.     GifRecordType RecordType;
  222.     GifByteType *Extension;
  223.  
  224.     /* Scan the content of the GIF file, until image descriptor is detected: */
  225.     do {
  226.     if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR)
  227.         return GIF_ERROR;
  228.  
  229.     switch (RecordType) {
  230.         case IMAGE_DESC_RECORD_TYPE:
  231.         return DGifGetImageDesc(GifFile);
  232.         case EXTENSION_RECORD_TYPE:
  233.         /* Skip any extension blocks in file: */
  234.         if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR)
  235.             return GIF_ERROR;
  236.  
  237.         while (Extension != NULL)
  238.             if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR)
  239.             return GIF_ERROR;
  240.         break;
  241.         case TERMINATE_RECORD_TYPE:
  242.         break;
  243.         default:            /* Should be traps by DGifGetRecordType. */
  244.         break;
  245.     }
  246.     }
  247.     while (RecordType != TERMINATE_RECORD_TYPE);
  248.  
  249.     return GIF_ERROR;          /* We should be here - no image was found! */
  250. }
  251.  
  252. /******************************************************************************
  253. * Create union of the two given color maps and return it. If result can not   *
  254. * fit into 256 colors, GIF_ERROR is returned, GIF_OK otherwise.              *
  255. * ColorIn1 is copied as it to ColorUnion, while colors from ColorIn2 are      *
  256. * copied iff they dont exists before. ColorTransIn2 is used to map old          *
  257. * ColorIn2 into ColorUnion color map table.                      *
  258. ******************************************************************************/
  259. static int UnionColorMap(GifColorType *ColorIn1, int ColorIn1Size,
  260.              GifColorType *ColorIn2, int ColorIn2Size,
  261.              GifColorType **ColorUnionPtr, int *ColorUnionSize,
  262.              GifPixelType ColorTransIn2[])
  263. {
  264.     int i, j, CrntSlot;
  265.     GifColorType *ColorUnion;
  266.  
  267.     /* Allocate table which will hold result for sure: */
  268.     *ColorUnionPtr = ColorUnion = (GifColorType *) malloc(sizeof(GifColorType)
  269.     * (ColorIn1Size > ColorIn2Size ? ColorIn1Size : ColorIn2Size) * 2);
  270.  
  271.     /* Copy ColorIn1 to ColorUnionSize; */
  272.     for (i = 0; i < ColorIn1Size; i++) ColorUnion[i] = ColorIn1[i];
  273.     CrntSlot = ColorIn1Size;                  /* Current Empty slot. */
  274.  
  275.     /* Copy ColorIn2 to ColorUnionSize (use old colors if exists): */
  276.     for (i = 0; i < ColorIn2Size && CrntSlot<=256; i++) {
  277.     /* Let see if this color already exists: */
  278.     for (j = 0; j < ColorIn1Size; j++) {
  279.         /* If memcmp does not exists for you, use the following: */
  280.         /*
  281.         if (ColorIn1[j].Red   == ColorIn2[i].Red &&
  282.         ColorIn1[j].Green == ColorIn2[i].Green &&
  283.         ColorIn1[j].Blue  == ColorIn2[i].Blue) break;
  284.         */
  285.         if (memcmp(&ColorIn1[j], &ColorIn2[i], 3) == 0) break;
  286.     }
  287.     if (j < ColorIn1Size) {
  288.         /* We found this color aleardy exists in ColorIn1: */
  289.         ColorTransIn2[i] = j;
  290.     }
  291.     else {
  292.         /* Its new - copy it to a new slot: */
  293.         ColorUnion[CrntSlot] = ColorIn2[i];
  294.         ColorTransIn2[i] = CrntSlot++;
  295.     }
  296.     }
  297.  
  298.     if (CrntSlot > 256) return GIF_ERROR;
  299.  
  300.     /* Complete the color map to a power of two: */
  301.     for (i = 1; i <= 8; i++) if ((1 << i) >= CrntSlot) break;
  302.     for (j = CrntSlot; j < (1 << i); j++)
  303.     ColorUnion[j].Red = ColorUnion[j].Green = ColorUnion[j].Blue = 0;
  304.  
  305.     *ColorUnionSize = i;
  306.  
  307.     return GIF_OK;
  308. }
  309.  
  310. /******************************************************************************
  311. * Close both input and output file (if open), and exit.                  *
  312. ******************************************************************************/
  313. static void QuitGifError(GifFileType *GifFileIn1, GifFileType *GifFileIn2,
  314.              GifFileType *GifMaskFile, GifFileType *GifFileOut)
  315. {
  316.     PrintGifError();
  317.     if (GifFileIn1 != NULL) DGifCloseFile(GifFileIn1);
  318.     if (GifFileIn2 != NULL) DGifCloseFile(GifFileIn2);
  319.     if (GifMaskFile != NULL) DGifCloseFile(GifMaskFile);
  320.     if (GifFileOut != NULL) EGifCloseFile(GifFileOut);
  321.     exit(1);
  322. }
  323.